﻿using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace WinSupperUpdateService.Service
{
	internal class SoftwareUpdate
	{
		// 更新软件包操作包操作的临时根目录
		internal static readonly string SofwareUpateRootPackagePath = Path.Combine(Path.GetTempPath(), "FxWinSupper");
		// 下载后更新包文件路径
		internal static readonly string TmpSofwareUpatePackageZipPath = Path.Combine(SofwareUpateRootPackagePath, "updatePackage.zip");
		// 更新包解压后的文件夹目录
		internal static readonly string SofwareUpatePackagDecompressionPath = Path.Combine(SofwareUpateRootPackagePath, "software");
		// 旧软件包备份路径
		internal static readonly string SofwareUpatePackagBackupPath = Path.Combine(SofwareUpateRootPackagePath, "backup");

		public static void Main(string[] args)
		{
			Console.Title = "FxWinSupper Update";
			if (args.Length < 1)
			{
				Console.WriteLine("缺少参数arg0: 软件主目录");
				return;
			}

			string softwareDir = args[0].Replace("\"", "");
			try
			{
				UpdateMainSoftware(softwareDir);
			}
			catch (Exception e)
			{
				Console.WriteLine($"更新出错: {e.Message} {e.StackTrace}");
				Console.WriteLine("正在回滚更新");
				CopyDirectory(new DirectoryInfo(SofwareUpatePackagBackupPath), new DirectoryInfo(softwareDir));
				Console.WriteLine("回滚完成，please press any key exit...");
				Console.ReadKey();
				StartMainSoftware($"{softwareDir}\\FxWinSuper.exe");
			}
		}

		private static void UpdateMainSoftware(string softwareDir)
		{
			Console.WriteLine("正在进行更新前检测...");
			if (!Directory.Exists(softwareDir))
			{
				Console.WriteLine($"软件目录不存在: {softwareDir}");
				return;
			}

			if (!Directory.Exists(SofwareUpatePackagDecompressionPath))
			{
				Console.WriteLine($"未获取到新软件包: {SofwareUpatePackagDecompressionPath}");
				return;
			}

			// 杀主程序
			Process[] processes = Process.GetProcessesByName("FxWinSuper.exe");
			DateTime startTime = DateTime.UtcNow;
			while (processes.Length > 0)
			{
				processes = Process.GetProcessesByName("FxWinSuper.exe");
				if (processes.Length > 0 && (DateTime.UtcNow - startTime).Seconds >= 5)
				{
					foreach (Process process in processes)
					{
						process.Kill();
					}
				}
			}

			try
			{
				Console.WriteLine($"正在备份原软件目录至[{SofwareUpatePackagBackupPath}]");
				CopyDirectory(new DirectoryInfo(softwareDir), new DirectoryInfo(SofwareUpatePackagBackupPath));
				Console.WriteLine("正在进行软件更新，请稍等...");
				foreach (DirectoryInfo directory in new DirectoryInfo(SofwareUpatePackagDecompressionPath).GetDirectories())
				{
					string sourceMapDir = Path.Combine(softwareDir, directory.Name);
					if (Directory.Exists(sourceMapDir))
					{
						Directory.Delete(sourceMapDir, true);
					}
				}
				CopyDirectory(new DirectoryInfo(SofwareUpatePackagDecompressionPath), new DirectoryInfo(softwareDir));
				Console.WriteLine("软件更新完成");
				Thread.Sleep(1000);
				StartMainSoftware($"{softwareDir}\\FxWinSuper.exe");
			}
			catch (Exception e)
			{
				throw new UpdateException(e.Message, e);
			}
		}

		/// <summary>
		/// 复制文件夹内所有文件到目标目录
		/// </summary>
		private static void CopyDirectory(DirectoryInfo source, DirectoryInfo target)
		{
			if (!target.Exists)
			{
				try
				{
					Directory.CreateDirectory(target.FullName);
				}
				catch (Exception e)
				{
					Console.WriteLine($"创建目录：[{target.FullName}]失败, {e.Message}");
				}
			}
			foreach (FileInfo fi in source.GetFiles())
			{
				try
				{
					fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
				}
				catch (Exception e)
				{
					Console.WriteLine($"拷贝文件:[{fi.FullName}]失败, {e.Message}");
				}
			}
			foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
			{
				try
				{
					DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name);
					CopyDirectory(diSourceSubDir, nextTargetSubDir);
				}
				catch (Exception e)
				{
					Console.WriteLine($"创建目录:[{diSourceSubDir.Name}失败], {e.Message}");
				}
			}
		}

		public static void StartMainSoftware(string filepath)
		{
			string path = Path.GetDirectoryName(filepath);
			string exeName = Path.GetFileName(filepath);
			Process process = new Process();
			process.StartInfo.FileName = "cmd.exe";
			process.StartInfo.Arguments = $"/c cd \"{path}\" && {exeName}";
			process.StartInfo.CreateNoWindow = true;
			process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
			process.StartInfo.UseShellExecute = true;
			process.StartInfo.Verb = "runas";
			process.Start();
		}

		public static void ExecUpdate(string softwarePath, int delay = 3)
		{
			string path = Path.GetDirectoryName(typeof(SoftwareUpdate).Assembly.Location);
			string exeName = "WinSupperUpdateService.exe";
			Process process = new Process();
			process.StartInfo.FileName = "cmd.exe";
			process.StartInfo.Arguments = $"/c title FxWinSupper Update && echo Wait Update... && timeout /t {delay} > nul && cd \"{path}\" && {exeName} \"{softwarePath}\"";
			process.StartInfo.UseShellExecute = true;
			process.StartInfo.Verb = "runas";
			process.Start();
		}
	}

	internal class UpdateException : Exception
	{
		public UpdateException(string msg, Exception innerException) : base(msg, innerException){}
	}
}
